package com.tlvip.design.factory.v1;

/**
 * <p>description：</p>
 * <p>
 * 引入设计模式的前提：找到代码中稳定的部分和变化的部分
 * <p>
 * 使类的实现延迟到子类
 * <p>
 * 应用场景：
 * 当你不知道该使用对象的确切类型的时候
 * 当你希望为库或者框架提供扩展其内部组件的方法时
 * <p>
 * 优点：
 * 将具体的产品和创建者解耦
 * 符合单一职责原则
 * 符合开闭原
 * <p>
 * jdk源码中静态工厂
 * Calendar
 * NumberFormatter.getInstance
 * ResourceBundle.getBundle
 * <p>
 * 工厂方法
 * java.net.URLStreamHandlerFactory
 * javax.xml.bind.JAXBContext.createMarshaller
 *
 * 三者区别
 *  TestFactory 用Application调用工厂，并通过传type来实例化不同产品，当增加产品时，需要修改SimpleFactory。
 *
 *  TestFactoryV1 抽象Application，
 *     将变化的部分createProduct()延迟到子类中实现
 *     将固定部分getObject()保留在父类中。
 *     通过实例化不同的Application来获取对应的产品实例
 *     避免对Application的修改，降低编码风险。
 *
 *  TestAbstractFactory
 *     顶层接口定义规范，IConnection，ICommand，并定义IDatabaseUtils来组合抽象接口
 *     具体实现交由不同客户端，
 *     最终调用仍然按照约定方式来
 *     不依赖于具体实现，解耦客户端
 *
 * <p>copyright： copyright(C)2016-2099</p>
 * <p>Life is short,we need passion</p>
 * <p>Summary： </p>
 * <p>instructions： </p>
 * Date 2021/8/15</p>
 * Author mac
 *
 * @version 1.0
 */
public class TestFactoryV1 {
    public static void main(String[] args) {
        Application application = new ConcreteProductA();
        Product product = application.getObject();
        product.method1();

        System.out.println("-----------------");

        Application a1Application = new ConcreteProductA1();
        Product product1 = a1Application.getObject();
        product1.method1();
    }

}

interface Product {

    // 稳定的部分，每个产品实现可能不同
    void method1();
}

// 每个产品是变化的部分
class ProductA implements Product {
    public void method1() {
        System.out.println("ProductA.method1 execute.");
    }

}

class ProductA1 implements Product {
    public void method1() {
        System.out.println("ProductA1.method1 execute.");
    }
}

// 原来面向实现的方式，需要改进
//class Application {
//    private ProductA createProduct() {
//        return new ProductA();
//    }
//
//    ProductA getObject() {
//        ProductA product = createProduct();
//        return product;
//    }
//}

abstract class Application {
    // 变化的部分，延迟到子类中实现
    abstract Product createProduct();

    // 不变的部分
    Product getObject() {
        Product product = createProduct();
        return product;
    }
}

class ConcreteProductA extends Application {

    @Override
    Product createProduct() {
        return new ProductA();
    }
}

class ConcreteProductA1 extends Application {

    @Override
    Product createProduct() {
        return new ProductA1();
    }
}